/**
 * Copyright 2012 Alfredo "Rainbowbreeze" Morresi
 * 
 * This file is part of Eureka! project.
 * 
 * Eureka! is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Eureka! is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with Eureka!. If not, see http://www.gnu.org/licenses/.
 */
package it.rainbowbreeze.eureka.data;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;


/**
 * @author Alfredo "Rainbowbreeze" Morresi
 *
 */
public class EurekaProvider extends ContentProvider {

    // ------------------------------------------ Private Fields
    private static SQLiteDatabase mWritableDB;
    private static SQLiteDatabase mReadableDB;
    
    private static final int URI_POINTS = 1;
    private static final int URI_SINGLE_POINT = 2;
    
    private static final UriMatcher sUriMatcher;
    static {
        //TODO see help of this constructor for complex addURI examples
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        //pots
        sUriMatcher.addURI(EurekaContract.AUTHORITY, EurekaContract.QualityPoint.PATH, URI_POINTS);
        sUriMatcher.addURI(EurekaContract.AUTHORITY, EurekaContract.QualityPoint.PATH + "/#", URI_SINGLE_POINT);
    }

    // -------------------------------------------- Constructors
    public EurekaProvider() {
    }

    // --------------------------------------- Public Properties

    // -------------------------------------------------- Events
    @Override
    public boolean onCreate() {
       Context context = getContext();
       DatabaseHelper dbHelper = new DatabaseHelper(context);
//       DatabaseHelper dbHelper = new DatabaseHelper(context, mLogFacility);
       mWritableDB = dbHelper.getWritableDatabase();
       mReadableDB = dbHelper.getReadableDatabase();
       return (mWritableDB == null) ? false : true;
    }

    // ------------------------------------------ Public Methods
    @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case URI_POINTS:
            return EurekaContract.QualityPoint.CONTENT_TYPE;
        case URI_SINGLE_POINT:
            return EurekaContract.QualityPoint.CONTENT_TYPE_ITEM;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        String tableName = null;
        String finalSelection = null;
        
        switch (sUriMatcher.match(uri)) {
            case URI_POINTS:
                tableName = EurekaContract.QualityPoint.TABLE_NAME;
                finalSelection = selection;
                break;

            case URI_SINGLE_POINT:
                tableName = EurekaContract.QualityPoint.TABLE_NAME;
                finalSelection = createSelectionForColumn(
                        selection, EurekaContract.QualityPoint._ID, getPointIdFromUri(uri));
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        int affected = mWritableDB.delete(tableName, finalSelection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return affected;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        int uriMatch = sUriMatcher.match(uri);
        if (uriMatch != URI_POINTS) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }
        
        String tableName = null;
        String nullColumnHack = null;
        Uri contentUri = null;

        //prepare the real request
        switch (uriMatch) {
            case URI_POINTS:
                tableName = EurekaContract.QualityPoint.TABLE_NAME;
                nullColumnHack = EurekaContract.QualityPoint.SCORE;
                contentUri = EurekaContract.QualityPoint.CONTENT_URI;
                break;
        }

        long rowId = mWritableDB.insert(tableName, nullColumnHack, values);
        if (rowId > 0) {
            Uri newItemUri = ContentUris.withAppendedId(contentUri, rowId);
            getContext().getContentResolver().notifyChange(newItemUri, null);
            return newItemUri;
        } else {
            //TODO notify about the error
            //throw new SQLException("Failed to insert row into " + uri);
            return null;
        }
    }

    @Override
    public int update(
            Uri uri,
            ContentValues values,
            String selection,
            String[] selectionArgs) {
        String tableName = null;
        String finalSelection = null;
        
        switch (sUriMatcher.match(uri)) {
            case URI_POINTS:
                tableName = EurekaContract.QualityPoint.TABLE_NAME;
                finalSelection = selection;
                break;
                
            case URI_SINGLE_POINT:
                tableName = EurekaContract.QualityPoint.TABLE_NAME;
                finalSelection = createSelectionForColumn(
                        selection, EurekaContract.QualityPoint._ID, getPointIdFromUri(uri));
                break;
                
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        int affected = mWritableDB.update(tableName, values, finalSelection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return affected;
    }

    @Override
    public Cursor query(
            Uri uri,
            String[] projection,
            String selection,
            String[] selectionArgs,
            String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        
        //TODO: define a default sort order for each kind of data
        String defaultSortOrder = null;

        switch (sUriMatcher.match(uri)) {
            case URI_POINTS:
                //query for all pots
                qb.setTables(EurekaContract.QualityPoint.TABLE_NAME);
                defaultSortOrder = EurekaContract.QualityPoint.DEFAULT_SORT_ORDER;
                break;
               
            case URI_SINGLE_POINT:
                //query for a specific pot
                qb.setTables(EurekaContract.QualityPoint.TABLE_NAME);
                qb.appendWhere(EurekaContract.QualityPoint._ID + " = " + getPointIdFromUri(uri));
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        //put default sort order if another sort order is not specified
        if (TextUtils.isEmpty(sortOrder)) {
            sortOrder = defaultSortOrder;
        }

        Cursor c = qb.query(mReadableDB, projection, selection, selectionArgs, null, null, sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        int count = c.getCount();
        return c;
    }

    // ----------------------------------------- Private Methods
    /**
     * Finds the pot id from the URI
     * 
     * @param uri the URI where extract pot ID
     * @return the pot id, otherwise throws an {@link IllegalArgumentException}
     *         if URI is not valid
     */
    private long getPointIdFromUri(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case URI_SINGLE_POINT:
            return Long.parseLong(uri.getLastPathSegment());
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }
    
    private String createSelectionForColumn(String selection, String columnName, long columnValue) {
        return createSelectionForColumn(selection, columnName, String.valueOf(columnValue));
    }
    
    private String createSelectionForColumn(String selection, String columnName, String columnValue) {
        StringBuilder sb = new StringBuilder();
        
        sb.append(columnName).append(" = ").append(columnValue);
        if(!TextUtils.isEmpty(selection))
            sb.append(" AND (").append(selection).append(')');
        return sb.toString();
    }
 
    
    
    // ----------------------------------------- Private Classes
    private static class DatabaseHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "eureka.db";
        private static final int DATABASE_VERSION = 1;
        
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            StringBuilder sb = new StringBuilder();
            
            //for data types, refer to http://www.sqlite.org/datatype3.html 
            sb.append("CREATE TABLE ")
                .append(EurekaContract.QualityPoint.TABLE_NAME)
                .append(" (")
                .append(EurekaContract.QualityPoint._ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT, ")
                .append(EurekaContract.QualityPoint.ACQUISITION_TIMESTAMP).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.CATEGORYID).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.LATITUDE).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.LONGITUDE).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.MEASURE_ID).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.RADIUS).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.READING_TIMESTAMP).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.REFERRING_RADIUS).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.SCORE).append(" INTEGER, ")
                .append(EurekaContract.QualityPoint.VALUE).append(" INTEGER ")
                .append(");");
            String sqlStatement = sb.toString();
//            mLogFacility.v(LOG_HASH, "Executing SQL statement [" + sqlStatement + "]");
            db.execSQL(sqlStatement);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + EurekaContract.QualityPoint.TABLE_NAME);
            onCreate(db);
        }
    }
}
